package com.asp.aspchain.transaction.disruptor;

import com.asp.aspchain.core.dao.MgrContractMapper;
import com.asp.aspchain.core.dao.TransactionMapper;
import com.asp.aspchain.core.dao.ValidTransactionMapper;
import com.asp.aspchain.core.ethereum.EthService;
import com.asp.aspchain.core.model.MgrContractModel;
import com.asp.aspchain.core.model.TransactionModel;
import com.asp.aspchain.core.model.ValidTransactionModel;
import com.asp.aspchain.core.util.DateUtil;
import com.lmax.disruptor.EventHandler;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.web3j.protocol.core.methods.response.EthBlock;
import org.web3j.protocol.core.methods.response.Transaction;

import java.io.IOException;
import java.util.Date;
import java.util.List;

@Component
public class ListenDataIntoDBHandler implements EventHandler<ListenDataEvent> {
	private final static Logger logger = Logger.getLogger(ListenDataIntoDBHandler.class);
	@Autowired
	TransactionMapper transactionMapper;
	@Autowired
	ValidTransactionMapper validTransactionMapper;
	@Autowired
	MgrContractMapper mgrContractMapper;
	@Autowired
	EthService ethService;

	@Override
	public void onEvent(ListenDataEvent listenDataEvent, long sequence, boolean endOfBatch) throws Exception {
		long threadId = Thread.currentThread().getId();
		logger.info("IntoDB处理者的线程id" + threadId);
		EthBlock.Block blk = listenDataEvent.getBlk();
		List<EthBlock.TransactionResult> transactions = blk.getTransactions();
		//是我们系统的交易hash就记录进t_abc_transaction
		if (transactions != null && transactions.size() > 0) {
			for (EthBlock.TransactionResult transactionResult : transactions) {
				String transactionHash = (String) transactionResult.get();
				logger.info("交易hash：" + transactionHash);
				TransactionModel transaction = new TransactionModel();
				transaction.setTransactionid(transactionHash);
				transaction = transactionMapper.selectOne(transaction);
				//如果表里有记录，则是平台交易产生的记录，否则其他方式的交易记录在异常交易表里
				if (transaction != null) {
					setTransaction(listenDataEvent, blk, transaction.getTradeid());
				} else {
					setValidTransaction(blk, transactionHash);
				}
			}
		}
		//否则记进t_abc_valid_transaction
		setValidTransaction(blk, null);

	}

	private void setValidTransaction(EthBlock.Block blk, String transactionHash) throws IOException {
		ValidTransactionModel validTransaction = new ValidTransactionModel();
		validTransaction.setCreatetime(new Date());
		validTransaction.setUpdatetime(validTransaction.getCreatetime());
		validTransaction.setBlockhash(blk.getHash());
		validTransaction.setBlocktime(new Date(Long.parseLong(blk.getTimestamp().toString()) * 1000));
		if (StringUtils.isNotBlank(transactionHash)) {
			Transaction result = ethService.getTransactionByHash(transactionHash).getResult();
			String to = result.getTo();
			validTransaction.setFrom(result.getFrom());
			validTransaction.setTo(to);
			validTransaction.setTransationid(transactionHash);
			//1、to为空则是智能合约部署块 2、如果to是智能合约地址，说明执行了智能合约交易 3、其他情况是eoa交易块
			if (StringUtils.isBlank(to)) {
				validTransaction.setBlocktype(3);
			} else {
				MgrContractModel mgrContract = new MgrContractModel();
				mgrContract.setContractid(to);
				mgrContract = mgrContractMapper.selectOne(mgrContract);
				if (mgrContract != null) {
					validTransaction.setBlocktype(5);
				} else {
					validTransaction.setBlocktype(1);
				}
			}
		}else {
			//没有交易则为空块
			validTransaction.setBlocktype(4);
		}
		if (blk.getUncles().size() > 0) {
			//有叔块就加2
			validTransaction.setBlocktype(validTransaction.getBlocktype()*10+2);
		}
		validTransactionMapper.insert(validTransaction);
	}

	private void setTransaction(ListenDataEvent listenDataEvent, EthBlock.Block blk, String tradeid) {
		TransactionModel transactionModel = new TransactionModel();
		transactionModel.setTradeid(tradeid);
		transactionModel.setBlocktime(new Date(Long.parseLong(blk.getTimestamp().toString()) * 1000));
		transactionModel.setBlockhash(blk.getHash());
		transactionModel.setUpdatetime(new Date());
		transactionModel.setGas(blk.getGasUsed());
		transactionModel.setNonce(blk.getNonce());
		String notifyId = "NTF" + DateUtil.getAllTime();
		transactionModel.setNotifyid(notifyId);
		transactionMapper.updateById(transactionModel);
		listenDataEvent.getNotifyIdList().add(notifyId);
	}


}
